/**********************************************************************
	File: jtag_interface.v 
	
	Copyright (C) 2013  Alireza Monemi

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
	
	Purpose:
	The JTAG interface NI. can be used for sending and receiving packet from
	the board. It will be also used to program the NIOS microprocessors.



	cmd_ram[0] 	=	{any_vc_has_data , done, rd_no_pck_err, rd_ovr_size_err, ..... start,ram_wr,last_part,first_part,  start_rd,start_wr, start_prog,nios_reset};
	cmd_ram[1] 	= 	{des_x_addr,des_y_addr}
	cmd_ram[2]	= 	start_addr
	cmd_ram[3]	= 	packet_size
	
	Info: monemi@fkegraduate.utm.my
**********************************************************************/

`include "define.v"

module jtag_interface #(
	parameter VC_NUM_PER_PORT 			=	2,
	parameter PYLD_WIDTH 				=	32,
	parameter BUFFER_NUM_PER_VC		=	16,
	parameter FLIT_TYPE_WIDTH			=	2,
	parameter PORT_NUM					=	5,
	parameter X_NODE_NUM					=	4,
	parameter Y_NODE_NUM					=	3,
	parameter SW_X_ADDR					=	0,
	parameter SW_Y_ADDR					=	0,
	parameter NIC_CONNECT_PORT			=  3,	 // 0:Local  1:East, 2:North, 3:West, 4:South 
	parameter NIOS_RAM_WIDTH			=	13,
	parameter CMD_RAM_ADDR_WIDTH		=	5,
	parameter COD_RAM_ADDR_WIDTH		=	8,
	parameter CAND_VC_SEL_MODE			= 	0,
	parameter SHARED_MEM_ADDR_WIDTH	=	25,
	parameter FIFO_FULL_WIDTH			=	VC_NUM_PER_PORT*2,
	parameter VC_ID_WIDTH				=	VC_NUM_PER_PORT,
	parameter FLIT_WIDTH					=	PYLD_WIDTH+FLIT_TYPE_WIDTH+VC_ID_WIDTH
	
	
)
(
	
	
	input												clk,
	input 											reset,
	output											nios_reset,   	
	output											led,
		
	//synthesis translate_off
		
	input	[31								:0]	cmd_data,
	input [CMD_RAM_ADDR_WIDTH-1		:0]	cmd_addr,
	input												cmd_we,
	output[31:								0]		cmd_q_b,
	
	
	input	[31								:0]	code_data,
	input [COD_RAM_ADDR_WIDTH-1		:0]	code_addr,
	input												code_we,
	output											code_q_b,
	
	//synthesis translate_on
	
	// NOC interfaces
	output	[FLIT_WIDTH-1				:0] 	flit_out,     
	output 	reg    			   				flit_out_wr,   
	input		[VC_NUM_PER_PORT-1		:0]	credit_in,
	
	input		[FLIT_WIDTH-1				:0] 	flit_in,     
	input 		   			   				flit_in_wr,   
	output reg	[VC_NUM_PER_PORT-1	:0]	credit_out
	
	
);
	`LOG2
	localparam PORT_NUM_BCD_WIDTH			=	log2(PORT_NUM);
	localparam	CMD_DATA_NUM			=	5;	
	localparam	FLAGS_NUM				=	7;
	localparam	ACK_NUM					=	4;
	
	
	localparam	CMD_COUNTER_WIDTH		=	log2(CMD_DATA_NUM+1);		
	
	localparam	STATE_NUM				=	10;
	
	localparam	RST						=	1; 	
	localparam	IDEAL						=	2;
	localparam	RD_CMD					=	4;
	localparam	CHECK_STARTS			=	8;
	localparam	SND_HDR					=	16;
	localparam	SEND_RAM_ADDR			=	32;
	localparam	WR_ON_FIFO				=	64;
	localparam	WR_ON_RAM				=	128;
	localparam	DONE						=	256; 
	localparam	WAIT						=	512;
				
		
	localparam WAIT_COUNT				=	127;
	localparam WAIT_COUNT_WIDTH		=	log2(WAIT_COUNT);
	
	
	
	localparam	HDR_FLIT					=			2'b10;
	localparam	BDY_FLIT					=			2'b00;
	localparam	TAIL_FLIT				=			2'b01;
	
	localparam	COUNTER_WIDTH			=	COD_RAM_ADDR_WIDTH+1;
	localparam	PTR_WIDTH				=	COD_RAM_ADDR_WIDTH+1;
	localparam	PCK_SIZE_WIDTH			=	COD_RAM_ADDR_WIDTH+1;

	
	
	localparam 	X_NODE_NUM_WIDTH		=			log2(X_NODE_NUM);
	localparam 	Y_NODE_NUM_WIDTH		=			log2(Y_NODE_NUM);
	
	
	localparam	ZERO_NUM_HDR			=			32-PORT_NUM_BCD_WIDTH-X_NODE_NUM_WIDTH-Y_NODE_NUM_WIDTH-X_NODE_NUM_WIDTH-Y_NODE_NUM_WIDTH-1;
	
	
	
	wire	[COD_RAM_ADDR_WIDTH-1	:		0]		code_ram_address;
	wire	[CMD_RAM_ADDR_WIDTH-1	:		0]		cmd_ram_address;
	reg	[FLAGS_NUM-1				:		0]		flags,flags_next;
	wire	[31							:		0]		code_ram_data_in, code_ram_data_out,cmd_ram_data_in;
	wire	[31							:		0]		cmd_ram_data_out;
	wire													code_ram_wren;
	reg													cmd_ram_wren;
	reg 													wait_counter_inc,wait_counter_rst;
	reg 	[WAIT_COUNT_WIDTH-1		:		0]		wait_counter_next,wait_counter;
	
	reg	[STATE_NUM-1				:		0]		ps,ns;		
	
	wire													start_prog,first_part,last_part,start_wr,start_rd,start,ram_wr_start;
	reg													start_reg;
	reg	[X_NODE_NUM_WIDTH-1		:		0]		des_x_addr,des_x_addr_next;
	reg	[Y_NODE_NUM_WIDTH-1		:		0]		des_y_addr,des_y_addr_next;
	reg 	[PTR_WIDTH-1				:		0]		memory_ptr,memory_ptr_next;
	reg 	[PCK_SIZE_WIDTH-1			:		0]		pck_size,pck_size_next;
	reg	[SHARED_MEM_ADDR_WIDTH-1:		0]		shared_mem_addr,shared_mem_addr_next;	
	reg													done,done_next;
	
	
	
	wire													pck_eq_counter;
	
	reg	[COD_RAM_ADDR_WIDTH		:		0]	   counter,counter_next;
	reg													counter_reset;
	reg													counter_increase;
	
	
	
	reg  [PORT_NUM_BCD_WIDTH-1		:		 0]	port_num;
	wire [PORT_NUM_BCD_WIDTH-1		:		 0]	port_num_next;
	
	
	reg	[FLIT_TYPE_WIDTH-1		:		0]		wr_flit_type;//,flit_type_next;
	
	wire	[31							:		0]		pyld;

	
	reg 													flit_out_wr_next;
	wire 													nios_reset_cmd;
	
	
	//reg 										wr_done_next, wr_done;
	//reg										rd_done_next, rd_done;
	reg										rd_no_pck_err_next,	rd_no_pck_err;
	reg										rd_ovr_size_err_next, rd_ovr_size_err;
	reg										wr_mem_en_next,wr_mem_en;
	
	
	reg										cand_wr_vc_en, hdr_en,ram_addr_en;
	wire										cand_wr_vc_full;
	reg [VC_NUM_PER_PORT-1	:	0]		cand_rd_vc,cand_rd_vc_next;
	wire 										no_rd_vc_is_cand;
	reg										cand_rd_vc_en,cand_rd_vc_rst;
	wire										cand_rd_vc_not_empty;
	reg										any_vc_has_data;
	
		
	
	wire [VC_NUM_PER_PORT-1	:	0]		rd_vc_arbiter_in ,rd_vc_arbiter_out; 
	reg       	   						ififo_rd_en; 
	
	
	
	wire										all_vcs_full;
	reg 										mem_wr;
	reg										fifo_wr;
	
	
	
	
	
	wire 	[FLIT_WIDTH-1			:0]	ififo_dout;   
	wire	[VC_NUM_PER_PORT-1	:0]	ififo_vc_not_empty;
	wire 										ififo_tail_flg;
	wire 	[VC_NUM_PER_PORT-1	:0]	flit_in_vc_num;
	
	
	
	wire 	[VC_NUM_PER_PORT-1	:0]	full_vc;
	wire 	[VC_NUM_PER_PORT-1	:0]	cand_wr_vc;
	
	
	reg [CMD_COUNTER_WIDTH-1		:	0] cmd_counter ,cmd_counter_next;
	reg											cmd_counter_rst,cmd_counter_inc;
	
	reg											cmd_updated,cmd_updated_next;
	
	wire											any_start_asserted;
	
	assign	nios_reset								= nios_reset_cmd | reset;
	assign 	{ram_wr_start,last_part,first_part,start_rd,start_wr,start_prog,nios_reset_cmd}			=	flags;
	
	
	
	
	assign	flit_out				=	{wr_flit_type,cand_wr_vc,pyld};
	assign	led 					=	(ps== WR_ON_RAM);
	
	
	assign	all_vcs_full  				=	& full_vc;
	assign	cand_wr_vc_full			=	| ( full_vc & cand_wr_vc);
			
	
	assign 	no_rd_vc_is_cand			=	~(| cand_rd_vc);
	assign 	rd_vc_arbiter_in			=	(cand_rd_vc_en)?  ififo_vc_not_empty : {VC_NUM_PER_PORT{1'b0}} ;
   assign 	cand_rd_vc_not_empty		=	|(ififo_vc_not_empty & cand_rd_vc) ;
	
	assign 	cmd_ram_data_in	=	{any_vc_has_data , done, rd_no_pck_err, rd_ovr_size_err, {(32-FLAGS_NUM-ACK_NUM){1'b0}},flags};
	
	
	assign 	code_ram_wren				=	wr_mem_en;

	
	assign	code_ram_data_in			=	{ififo_dout[31:0]};
	
	
	
	
	
	assign	pyld	 =	(hdr_en			)? {port_num,des_x_addr,des_y_addr,SW_X_ADDR[X_NODE_NUM_WIDTH-1	:	0], SW_Y_ADDR[Y_NODE_NUM_WIDTH-1	:	0],{ZERO_NUM_HDR{1'b0}},(start_prog|ram_wr_start)}: 
							(ram_addr_en	)?	{{(32-SHARED_MEM_ADDR_WIDTH){1'b0}}, shared_mem_addr } :
													code_ram_data_out;
													
													
	assign   start = cmd_ram_data_out[`JTAG_START_LOC];
	assign	any_start_asserted = start_prog | start_rd | start_wr | ram_wr_start;

	assign ififo_tail_flg				=	ififo_dout	[`FLIT_TAIL_FLAG_LOC	];
	
	assign flit_in_vc_num				=  flit_in	 	[`FLIT_IN_VC_LOC		];
	
	
	
	
	generate 
		if(COD_RAM_ADDR_WIDTH	>	 PTR_WIDTH) 	assign	code_ram_address					=	memory_ptr+	counter;
		else 													assign	code_ram_address					=	memory_ptr[COD_RAM_ADDR_WIDTH-1	:0 ] + counter [COD_RAM_ADDR_WIDTH-1	:0 ];
	
		if(COUNTER_WIDTH	> 	PCK_SIZE_WIDTH )  	assign 	pck_eq_counter				= ( counter[PCK_SIZE_WIDTH-1:	0] == pck_size);
		else 													assign 	pck_eq_counter				= ( counter == pck_size[COUNTER_WIDTH-1	:0]);
		
	endgenerate																					
	
		assign cmd_ram_address	= {{(CMD_RAM_ADDR_WIDTH-CMD_COUNTER_WIDTH){1'b0}},cmd_counter};

	
	
	
	
`ifdef MODEL_TECH
  // code for simulation with modelsim
  
  dual_port_ram #(.DATA_WIDTH (32),.ADDR_WIDTH(COD_RAM_ADDR_WIDTH), .CORE_NUMBER(8'hFF))
	the_code_ram
	(
	.clk			(clk),
	.data_a		(code_ram_data_in),
	.addr_a		(code_ram_address),
	.we_a			(code_ram_wren),
	.q_a			(code_ram_data_out),
	
	.data_b		(code_data),
	.addr_b		(code_addr),
	.we_b			(code_we),
	.q_b			(code_q_b)
);
	
	dual_port_ram #(.DATA_WIDTH (32),.ADDR_WIDTH(CMD_RAM_ADDR_WIDTH))
	the_cmd_ram
	(
	.clk			(clk),
	.data_a		(cmd_ram_data_in),
	.addr_a		(cmd_ram_address),
	.we_a			(cmd_ram_wren),
	.q_a			(cmd_ram_data_out),
	
	.data_b		(cmd_data),
	.addr_b		(cmd_addr),
	.we_b			(cmd_we),
	.q_b			(cmd_q_b)
);
	
	
  
  
  
`else
  // code for synthesis
  
  code_ram	the_code_ram
	(
		.address			(code_ram_address),
		.clock			(clk),
		.data				(code_ram_data_in),
		.wren				(code_ram_wren),
		.q					(code_ram_data_out)
	);

	

	comand_ram	the_cmd_ram
	(
		.address			(cmd_ram_address),
		.clock			(clk),
		.data				(cmd_ram_data_in),
		.wren				(cmd_ram_wren),
		.q					(cmd_ram_data_out)
	);
  
  
`endif
	
	
	fifo_buffer #(
	.VC_NUM_PER_PORT			(VC_NUM_PER_PORT),
	.FLIT_WIDTH					(FLIT_WIDTH ),
	.BUFFER_NUM_PER_VC		(BUFFER_NUM_PER_VC),
	.ENABLE_MIN_DEPTH_OUT	(0) // if 1 then the VC with minimum depth is merged with vc_nearly_full as output
	
	
	)	
	the_ififo
	(
	.din						(flit_in),     // Data in
	.vc_num_wr				(flit_in_vc_num),//write vertual channel 	
	.wr_en					(flit_in_wr),   // Write enable
	.vc_num_rd				(cand_rd_vc),//read vertual channel 	
	.rd_en					(ififo_rd_en),   // Read the next word
	.dout						(ififo_dout),    // Data out
	.vc_nearly_full		(),
	.vc_not_empty			(ififo_vc_not_empty),
	
		
	.reset					(reset),
	.clk						(clk)
	);

	
	
	arbiter #(
		.ARBITER_WIDTH (VC_NUM_PER_PORT),
		.CHOISE			(1)  // 0 blind round-robin and 1 true round robin
)
rd_vc_arbiter
(	
	.clk			(clk), 
   .reset 		(reset), 
   .request	 	(rd_vc_arbiter_in), 
   .grant		(rd_vc_arbiter_out), 
   .anyGrant	()
);

	
	
	xy #(
		.PORT_NUM			(PORT_NUM),
		.X_NODE_NUM			(X_NODE_NUM),
		.Y_NODE_NUM			(Y_NODE_NUM),
		.SW_X_ADDR			(SW_X_ADDR),
		.SW_Y_ADDR			(SW_Y_ADDR),
		.SENDER_PORT		(NIC_CONNECT_PORT)	 // 0:Local  1:East, 2:North, 3:West, 4:South 
	)
	the_xy
	(
		.dest_x_node_in	(des_x_addr),
		.dest_y_node_in	(des_y_addr),
		.port_num_out		(port_num_next)
	);
	
	
	always @(*)begin
		ns							=	ps;
		cmd_ram_wren 			=	1'b0;
		counter_reset			=	1'b0;
		counter_increase		=	1'b0;
		cmd_counter_rst		=	1'b0;
		cmd_counter_inc		=	1'b0;
		flit_out_wr_next		=	1'b0;
		wr_flit_type			=	BDY_FLIT;
		cand_rd_vc_rst			= 1'b0;
		cand_rd_vc_en			= 1'b0;
		cand_rd_vc_rst			= 1'b0;
		ififo_rd_en				= 1'b0;  
		wr_mem_en_next			= 1'b0;
		credit_out				= {VC_NUM_PER_PORT{1'b0}};
		cand_wr_vc_en			= 1'b0;
		hdr_en 					= 1'b0;
		done_next				= done;	
		//wr_done_next			= wr_done;
		//rd_done_next			= rd_done;
		rd_no_pck_err_next	= rd_no_pck_err;
		rd_ovr_size_err_next	= rd_ovr_size_err;
		cmd_updated_next		= cmd_updated;	
		wait_counter_rst		= 1'b0;
		wait_counter_inc		= 1'b0;
		ram_addr_en				= 1'b0;
			
		
		
		case(ps) 
			RST: begin
					cmd_ram_wren 	=	1'b1;
					ns					=	IDEAL;
					
			end //RST
			
			
			
			IDEAL: begin
					cand_rd_vc_en		=	(no_rd_vc_is_cand)? 1'b1	:	1'b0;
					cmd_counter_rst	=	1'b1;
					counter_reset		=	1'b1;
					wait_counter_rst  =	1'b1;
					if(start_reg) 			ns 				=	RD_CMD;
					else if( any_vc_has_data && ~ cmd_updated ) begin 
						ns = DONE;
						cmd_updated_next		=	1'b1;
					end
			end// IDEAL
			
			RD_CMD: begin
					if(cmd_counter ==  CMD_DATA_NUM ) 	begin 
						ns 	= (any_start_asserted)	? CHECK_STARTS  : DONE; 
						cmd_counter_rst	=	1'b1;
					end else cmd_counter_inc=	1'b1;
			end //RD_CMD
						
			CHECK_STARTS: begin
				done_next 					=	1'b0;
				if((start_prog  &&  first_part && ~all_vcs_full )|| start_wr || ram_wr_start) begin
						ns						=	SND_HDR;
						//prog_done_next		=	1'b0;
						
						cand_wr_vc_en		=	1'b1;
						flit_out_wr_next	= 	1'b1;
				end else if (start_prog  &&  ~first_part)	begin 
						ns						=	WR_ON_FIFO;
						//prog_done_next		=	1'b0;
						//wr_done_next		=	1'b0;
				end else if (start_rd) begin
						cmd_updated_next		=	1'b0;
						//rd_done_next			= 	1'b0;
						rd_ovr_size_err_next	=	1'b0;
						if(any_vc_has_data)	begin 
							//synthesis translate_off
							$display ("%d,\t   core (%d,%d) has recived a packet",$time,SW_X_ADDR,SW_Y_ADDR);
							//synthesis translate_on
							ns=	WR_ON_RAM;
							rd_no_pck_err_next= 1'b0;
							ififo_rd_en			= 1'b1; 
							credit_out			=	cand_rd_vc;
							wr_mem_en_next		= 1'b1;
						end else	begin
							ns=	DONE;
							rd_no_pck_err_next= 1'b1;
						end
				end 
			end //CHECK_STARTS
			
			SND_HDR: begin
				hdr_en = 1'b1;
				wr_flit_type = HDR_FLIT;
				if (ram_wr_start) begin 
					ns				 		=	SEND_RAM_ADDR;
					flit_out_wr_next	= 	1'b1;
				end else ns= WR_ON_FIFO;
			end
			
			SEND_RAM_ADDR: begin 
				ram_addr_en = 1'b1;
				ns		=		WR_ON_FIFO;
			end // SEND_RAM_ADDR
			
			WR_ON_FIFO:	begin 
					if(pck_eq_counter) begin
						ns					=	DONE;
						done_next		=	1'b1;
						//wr_done_next	=	start_wr;
						//prog_done_next	=	start_prog;
						if((last_part && start_prog ) || start_wr || ram_wr_start)	wr_flit_type	= TAIL_FLIT;	
					end else if(!cand_wr_vc_full) begin 
						flit_out_wr_next	= 1'b1;
						counter_increase	= 1'b1;
					end 
			end//WR_ON_FIFO
			
			WR_ON_RAM:	begin
				rd_no_pck_err_next= 1'b0;
				if(ififo_tail_flg) begin
					ns							=	DONE;
					//rd_done_next			=	1'b1;
					done_next				=	1'b1;
					cand_rd_vc_rst			=	1'b1;
				end 
				else begin //if ififo_tail_flg	 
					if(cand_rd_vc_not_empty ) begin
						ififo_rd_en				= 1'b1; 
						credit_out				=	cand_rd_vc;
						counter_increase		= 1'b1;
						
						if( pck_eq_counter ) begin
							rd_ovr_size_err_next	=	1'b1;
						
						end else begin// counter
							wr_mem_en_next	=	1'b1;
						
						end// else countert
					end// if(cand_rd_vc_not_empty )
				end// else ififo_tail_flg
			end//WR_ON_RAM:
			
			DONE : begin
					cmd_ram_wren 			=	1'b1;
					ns							= WAIT;
			end //WAIT
			WAIT	: begin 
				wait_counter_inc		=	1'b1;
				if(wait_counter == WAIT_COUNT) 			ns							=	IDEAL;
			end
		
		endcase
	end //always



	
	always@(*)begin
		
		counter_next	 		= 	counter;	
		cmd_counter_next		=	cmd_counter;
		pck_size_next			=	pck_size;
		flags_next				=	flags;
		memory_ptr_next		=	memory_ptr;
		des_x_addr_next		=	des_x_addr;
		des_y_addr_next		=	des_y_addr;
		cand_rd_vc_next		=  cand_rd_vc;
		wait_counter_next		=	wait_counter;
		shared_mem_addr_next	=	shared_mem_addr;
		
	
	
		if			(counter_reset)				counter_next		=	{COUNTER_WIDTH{1'b0}};
		else if	(counter_increase) 			counter_next		=  counter +1'b1;
		
		if			(cmd_counter_rst)				cmd_counter_next	=	{CMD_COUNTER_WIDTH{1'b0}};
		else if	(cmd_counter_inc) 			cmd_counter_next	=  cmd_counter +1'b1;
	
		case(cmd_counter)
			1: flags_next				=	cmd_ram_data_out	[FLAGS_NUM-1:	0];
			2: begin	
				des_y_addr_next   	=  cmd_ram_data_out	[Y_NODE_NUM_WIDTH-1								:	0]	;	
				des_x_addr_next   	=  cmd_ram_data_out	[Y_NODE_NUM_WIDTH+X_NODE_NUM_WIDTH-1		:	Y_NODE_NUM_WIDTH]	;	
				end 
			3: memory_ptr_next		=	cmd_ram_data_out	[PTR_WIDTH-1			:0];
			4: pck_size_next			=	cmd_ram_data_out	[PCK_SIZE_WIDTH-1		:0];
			5: shared_mem_addr_next	=	cmd_ram_data_out	[SHARED_MEM_ADDR_WIDTH-1	:0];
		
		endcase
		/*
		if			(cmd_counter == 1 )  		flags_next			=	cmd_ram_data_out	[5:	0];
		else if	(cmd_counter == 2 ) 	begin	
					des_y_addr_next   =  cmd_ram_data_out	[Y_NODE_NUM_WIDTH-1								:	0]	;	
					des_x_addr_next   =  cmd_ram_data_out	[Y_NODE_NUM_WIDTH+X_NODE_NUM_WIDTH-1		:	Y_NODE_NUM_WIDTH]	;	
		end 
		else if	(cmd_counter == 3 )	memory_ptr_next	=	cmd_ram_data_out	[PTR_WIDTH-1			:0];
		else if	(cmd_counter == 4 )  pck_size_next		=	cmd_ram_data_out	[PCK_SIZE_WIDTH-1		:0];
		else if	(cmd_counter == 5 )  shared_mem_addr_next	=	cmd_ram_data_out	[SHARED_MEM_ADDR_WIDTH-1		:0];
		*/
		if	(cand_rd_vc_rst) 			cand_rd_vc_next =	{VC_NUM_PER_PORT{1'b0}};
		else if(cand_rd_vc_en)		cand_rd_vc_next =	rd_vc_arbiter_out;
		
		if			(wait_counter_rst)				wait_counter_next	=	{WAIT_COUNT_WIDTH{1'b0}};
		else if	(wait_counter_inc) 			  wait_counter_next	=  wait_counter +1'b1;
		
	end//always

	
	
	
always @(posedge clk )begin
	if(reset)	begin
			ps						<=	RST;
			memory_ptr			<=	{PTR_WIDTH{1'b0}};
			pck_size				<=	{PCK_SIZE_WIDTH{1'b0}};
			des_x_addr			<=	{X_NODE_NUM_WIDTH{1'b0}};
			des_y_addr			<=	{Y_NODE_NUM_WIDTH{1'b0}};
			counter				<=	{COUNTER_WIDTH{1'b0}};
			shared_mem_addr	<=	{SHARED_MEM_ADDR_WIDTH{1'b0}};		
			cmd_counter			<=	{CMD_COUNTER_WIDTH{1'b0}};
			cand_rd_vc			<=	{VC_NUM_PER_PORT{1'b0}};
			port_num				<= {PORT_NUM_BCD_WIDTH{1'b0}};
			//wr_done				<=	1'b0;
			//rd_done				<=	1'b0;
			done					<=	1'b0;
			rd_no_pck_err		<=	1'b0;
			rd_ovr_size_err	<= 1'b0;
			wr_mem_en			<= 1'b0;
			flit_out_wr			<= 1'b0;
			any_vc_has_data	<= 1'b0;
			//prog_done			<= 1'b0;	
			flags					<=	{FLAGS_NUM{1'd0}};
			cmd_updated			<=	1'b0;
			start_reg			<= 1'b0;
			wait_counter		<= {WAIT_COUNT_WIDTH{1'b0}};
		
	end else begin//reset
			ps						<=	ns;
			memory_ptr			<=	memory_ptr_next;
			pck_size				<=	pck_size_next;
			des_x_addr			<=	des_x_addr_next;
			des_y_addr			<=	des_y_addr_next;
			counter				<=	counter_next;
			shared_mem_addr	<=	shared_mem_addr_next;	
			cmd_counter			<=	cmd_counter_next;
			cand_rd_vc			<=	cand_rd_vc_next;
			port_num				<= port_num_next;
			done					<=	done_next;
			//wr_done				<=	wr_done_next;
			//rd_done				<=	rd_done_next;
			rd_no_pck_err		<=	rd_no_pck_err_next;
			rd_ovr_size_err	<= rd_ovr_size_err_next;
			wr_mem_en			<= wr_mem_en_next;
			flit_out_wr			<= flit_out_wr_next;
			any_vc_has_data	<= | ififo_vc_not_empty;
			//prog_done			<= prog_done_next;	
			flags					<=	flags_next;
			cmd_updated			<=	cmd_updated_next;
			start_reg			<= start;
			wait_counter		<= wait_counter_next;
		
	end
end	


	wire [VC_NUM_PER_PORT-1			:0]		ovc_wr_in;
	assign ovc_wr_in	= (flit_out_wr ) ?  cand_wr_vc : {VC_NUM_PER_PORT{1'b0}};
	
	output_vc_status #(
		.VC_NUM_PER_PORT		(VC_NUM_PER_PORT),
		.BUFFER_NUM_PER_VC	(BUFFER_NUM_PER_VC),
		.CAND_VC_SEL_MODE		(CAND_VC_SEL_MODE)	// 0: use arbieration between not full vcs, 1: select the vc with moast availble free space
	)
	nic_ovc_status
	(
	.wr_in						(ovc_wr_in),   
	.credit_in					(credit_in),
	.full_vc						(full_vc),
	.cand_vc						(cand_wr_vc),
	.cand_wr_vc_en				(cand_wr_vc_en),
	.clk							(clk),
	.reset						(reset)
	);
	
//synthesis translate_off
always @(*) begin
	if(flit_in_wr && (flit_in[`FLIT_IN_VC_LOC]=={VC_NUM_PER_PORT{1'b0}})) $display ("%d,\t   Error: a packet has been recived by x[%d] , y[%d] with no assigned VC",$time,SW_X_ADDR,SW_Y_ADDR);
end


//synthesis translate_on

	
endmodule
	
	
	
	
	
	
	
	
	